package com.sdap2.common.utils;

import com.sdap2.common.constants.FboxConstants;
import com.sdap2.common.constants.YsConstants;
import com.sdap2.common.exception.BusinessException;
import com.sdap2.dto.DeviceDataRequest;
import com.sdap2.dto.DeviceDataResponse;
import com.sdap2.dto.FboxTokenResponse;
import com.sdap2.dto.YsTokenRequest;
import com.sdap2.dto.YsTokenResponse;
import com.sdap2.dto.YsCaptureResponse;
import com.sdap2.entity.Greenhouse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class WebClientUtil {
    
    private final WebClient webClient;
    private final RedisTemplate<String, String> redisTemplate;
    
    public String getFboxToken() {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("client_id", FboxConstants.CLIENT_ID);
        formData.add("client_secret", FboxConstants.CLIENT_SECRET);
        formData.add("scope", FboxConstants.SCOPE);
        formData.add("grant_type", FboxConstants.GRANT_TYPE);
        
        FboxTokenResponse response = webClient.post()
                .uri(FboxConstants.TOKEN_URL)
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .body(BodyInserters.fromFormData(formData))
                .retrieve()
                .bodyToMono(FboxTokenResponse.class)
                .block();
                
        if (response == null || response.getAccessToken() == null) {
            throw new BusinessException("获取Fbox token失败");
        }
        
        return response.getAccessToken();
    }
    
    public List<DeviceDataResponse> getDeviceData(Greenhouse greenhouse, List<String> deviceIds) {
        if (greenhouse.getAccessToken() == null) {
            greenhouse.setAccessToken(getFboxToken());
        }
        
        DeviceDataRequest request = new DeviceDataRequest();
        request.setIds(deviceIds);
        
        try {
            return webClient.post()
                    .uri(uriBuilder -> uriBuilder
                            .path(FboxConstants.DEVICE_DATA_URL)
                            .queryParam("boxNo", greenhouse.getBoxNo())
                            .build())
                    .contentType(MediaType.APPLICATION_JSON)
                    .header("Authorization", "Bearer " + greenhouse.getAccessToken())
                    .bodyValue(request)
                    .retrieve()
                    .bodyToFlux(DeviceDataResponse.class)
                    .collectList()
                    .block();
        } catch (Exception e) {
            if (e.getMessage().contains("401")) {
                greenhouse.setAccessToken(getFboxToken());
                return getDeviceData(greenhouse, deviceIds);
            }
            throw e;
        }
    }
    
    public String getYsToken() {
        // 先从Redis获取token
        String token = redisTemplate.opsForValue().get("ys:token");
        if (token != null) {
            return token;
        }
        
        YsTokenRequest request = new YsTokenRequest();
        request.setAccountId(YsConstants.ACCOUNT_ID);
        
        YsTokenResponse response = webClient.post()
                .uri(YsConstants.TOKEN_URL)
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(request)
                .retrieve()
                .bodyToMono(YsTokenResponse.class)
                .block();
                
        if (response == null || !"200".equals(response.getCode()) || response.getData() == null) {
            throw new BusinessException("获取萤石云token失败: " + response.getMsg());
        }
        
        token = response.getData().getAccessToken();
        // 设置过期时间比实际过期时间提前5分钟
        long expireIn = (response.getData().getExpireTime() - System.currentTimeMillis()) / 1000 - 300;
        redisTemplate.opsForValue().set("ys:token", token, expireIn, TimeUnit.SECONDS);
        
        return token;
    }
    
    public String captureCamera(String deviceSerial) {
        String token = getYsToken();
        
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("accessToken", token);
        formData.add("deviceSerial", deviceSerial);
        formData.add("channelNo", "1");
        formData.add("quality", "1");
        
        try {
            YsCaptureResponse response = webClient.post()
                    .uri(YsConstants.CAPTURE_URL)
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                    .body(BodyInserters.fromFormData(formData))
                    .retrieve()
                    .bodyToMono(YsCaptureResponse.class)
                    .block();
                
            if (response == null || !"200".equals(response.getCode()) || response.getData() == null) {
                throw new BusinessException("摄像头抓拍失败: " + response.getMsg());
            }
            
            return response.getData().getPicUrl();
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("摄像头抓拍失败: " + e.getMessage());
        }
    }
} 